<template>
  <div :id="'richedit-' + field.name">
    <div class="text-grey-7">{{field.label}}</div>
    <div class="q-pb-lg">
      <q-editor
        v-model="content"
        ref="richedit"
        :dense="$q.screen.lt.md"
        :readonly="field.readonly"
        :content-style="{ backgroundColor: field.readonly ? '#F2F2F2' : '#FFFFFF' }"
        :definitions="{
          upload: {
            tip: '上传图片',
            icon: 'image',
            handler: uploadIt
          },
          customize: {
            tip: field.customize && field.customize.tip || '自定义按钮',
            icon: field.customize && field.customize.icon || 'touch_app',
            handler: field.customize && field.customize.fn || customizeIt,
            label: field.customize && field.customize.label || ''
          }
        }"
        :toolbar="[
          [
            {
              label: $q.lang.editor.align,
              icon: $q.iconSet.editor.align,
              fixedLabel: true,
              options: ['left', 'center', 'right', 'justify']
            }
          ],
          ['bold', 'italic', 'strike', 'underline', 'subscript', 'superscript'],
          [
            {
              label: $q.lang.editor.formatting,
              icon: $q.iconSet.editor.formatting,
              list: 'no-icons',
              options: ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'code']
            },
            {
              label: $q.lang.editor.fontSize,
              icon: $q.iconSet.editor.fontSize,
              fixedLabel: true,
              fixedIcon: true,
              list: 'no-icons',
              options: ['size-1', 'size-2', 'size-3', 'size-4', 'size-5', 'size-6', 'size-7']
            },
            {
              label: $q.lang.editor.defaultFont,
              icon: $q.iconSet.editor.font,
              fixedIcon: true,
              list: 'no-icons',
              options: [ 'default_font', 'arial', 'arial_black', 'comic_sans', 'courier_new', 'impact', 'lucida_grande', 'times_new_roman', 'verdana']
            },
            'removeFormat'
          ],
          ['forecolor', 'backcolor'],
          ['quote', 'unordered', 'ordered', 'outdent', 'indent'],
          ['undo', 'redo'],
          ['upload', field.customize ? 'customize' : ''],
          ['viewsource']
        ]"
        :fonts="{
          arial: 'Arial',
          arial_black: 'Arial Black',
          comic_sans: 'Comic Sans MS',
          courier_new: 'Courier New',
          impact: 'Impact',
          lucida_grande: 'Lucida Grande',
          times_new_roman: 'Times New Roman',
          verdana: 'Verdana'
        }"
        @paste="evt => pasteCapture(evt)"
      >
        <template v-slot:forecolor>
          <q-btn-dropdown
            dense no-caps
            no-wrap
            unelevated
            label="颜色"
            size="sm"
            ref="forecolor"
          >
            <q-color
              @change="val => changeForeColor(val)"
              no-header
              no-footer
              default-view="palette"
            />
          </q-btn-dropdown>
        </template>
        <template v-slot:backcolor>
          <q-btn-dropdown
            dense no-caps
            no-wrap
            unelevated
            label="底色"
            size="sm"
            ref="backcolor"
          >
            <q-color
              @change="val => changeBackColor(val)"
              no-header
              no-footer
              default-view="palette"
            />
          </q-btn-dropdown>
        </template>
      </q-editor>
      <div class="hint" v-if="field.hint">{{field.hint}}</div>
    </div>

    <div class="bg-yellow-10 q-pa-xs" v-if="canShowCompare">
      <div class="text-bold text-white" style="padding: 1px; font-size: 12px;">
        {{ field.compare.label ? field.compare.label + '：' : ''}}
      </div>
      <div class="bg-white" v-html="field.compare.map ? field.compare.map.value : field.compare.value"></div>
    </div>

    <q-uploader
      ref="upload"
      url="/upload"
      flat
      multiple
      batch
      accept="image/*"
      label="上传照片"
      @uploaded="imageUploaded"
      @added="imageAdded"
      style="display: none;"
      :headers="headers"
    />
  </div>
</template>
<script>
import { defineComponent } from 'vue';
import DOMPurify from 'dompurify';

export default defineComponent({
  name: 'fieldRichedit',
  props: {
    field: {
      type: Object,
      default: () => {}
    }
  },
  emits: ['rich_customize_click'],
  data () {
    return {
      lastClip: null
    }
  },
  methods: {
    uploadIt (evt, proxy, caret) { // 富文本栏点击上传图片
      // console.log(evt, proxy, caret);
      this.$refs.upload.pickFiles(); // 触发选图片
    },
    imageAdded (files) { // 图片被添加后就上传
      this.$refs.upload.upload();
    },
    imageUploaded (info) { // 图片上传完毕
      const files = JSON.parse(info.xhr.responseText).images;
      this.field.value = (this.field.value || '') + files.map(v => `<img src="${v.url}" />`).join('');
    },
    customizeIt (evt, proxy, caret) { // 富文本栏点击自定义按钮
      this.$emit('rich_customize_click', caret.vm);
    },
    changeForeColor (color) {
      this.$refs.forecolor.hide();
      this.$refs.richedit.runCmd('foreColor', color);
    },
    changeBackColor (color, field) {
      this.$refs.backcolor.hide();
      this.$refs.richedit.runCmd('backColor', color);
    },
    headers () { // 加上用户token
      const items = [];
      if (this.$q.localStorage.getItem('token')) {
        items.push({
          name: 'Authorization',
          value: this.$q.localStorage.getItem('token')
        });
      }
      return items;
    },
    pasteCapture (e) {
      if (!this.lastClip || this.lastClip.timeStamp !== e.timeStamp) { // 防止相同的图片上传两次
        const items = (e.clipboardData || e.originalEvent.clipboardData).items;
        // console.log(items, Object.keys(items));
        for (const index in items) {
          const item = items[index];
          /* console.log(index, item); // word的html内容粘贴有问题，暂无法解决
          if (item.kind === 'string' && item.type === 'text/html') {
            item.getAsString((html) => {
              if (html.indexOf('urn:schemas-microsoft-com:office:office') >= 0) {
                // 正则表达式匹配 body 内容
                const bodyRegex = /<body[^>]*>([\s\S]*?)<\/body>/i;
                // 使用正则表达式提取 body 内容
                const match = html.match(bodyRegex);

                const str = match ? match[1] : html;

                this.content = str;
                console.log(this.content);
              }
            });
          } else  */
          if (item.kind === 'file' && item.type.includes('image/')) { // 图片上传
            const file = item.getAsFile();
            this.uploadImage(file);
          }
        }
        this.lastClip = e;
      }
    },
    uploadImage (file) {
      const formData = new FormData();
      formData.append('image', file);

      // 这里使用axios进行图片上传，你可以替换为你的上传方法
      this.$axios.post('/upload', formData, {
        headers: {
          'Content-Type': 'multipart/form-data'
        }
      })
        .then(({ data }) => {
          // 上传成功后，将图片URL插入到编辑器中
          // this.content += data.images.map(v => `<img src="${v.url}" />`).join('\n');
          this.content = this.replaceImgTags(this.content, data.images.map(v => v.url))
        })
        .catch(error => {
          console.error('上传失败', error);
        });
    },
    replaceImgTags (html, replacementUrl) {
      let idx = 0;
      // 正则表达式匹配 img 标签
      const regex = /<img\s+[^>]*>/gi;

      // 使用正则表达式找到所有 img 标签
      const matches = html.match(regex) || [];

      // 替换 src 为 base64 或本地文件路径的 img 标签
      let replacedHtml = html;
      for (const tag of matches) {
        // 正则表达式匹配 src 属性
        const srcRegex = /src\s*=\s*(["'])(data:image\/[a-z]+;base64,|file:[^"']*|[^"']*)\1/;
        const srcMatch = tag.match(srcRegex);
        // 如果 src 是 base64 或本地文件路径，则替换 src
        if (!srcMatch || (srcMatch && (srcMatch[2].startsWith('data:image/') || srcMatch[2].startsWith('file:')))) {
          // 构建新的 img 标签
          const newTag = `<img src="${replacementUrl[idx]}">`;
          idx++;

          replacedHtml = replacedHtml.replace(tag, newTag);
        }
      }

      return replacedHtml;
    }
  },
  computed: {
    content: {
      get () {
        return this.field.value;
      },
      set (val) {
        this.field.value = DOMPurify.sanitize(val);
      }
    },
    canShowCompare () {
      /*
        compare的值
        compare: {
          label, // 标题
          value, // 对比的值
          always // true-有数据就显示 false-值不同，再显示
        } */
      return this.field.compare && this.field.compare.value !== null && (this.field.compare.always || this.field.compare.value != this.field.value);
    }
  }
});
</script>

<style scoped>
.hint {
  font-size: 12px;
  min-height: 20px;
  line-height: 1;
  color: rgba(0, 0, 0, 0.54);
  padding: 8px 12px 0;
}
.compare {
  font-size: 12px;
  min-height: 20px;
  line-height: 1;
  padding: 8px 12px 0;
}
</style>
